using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using Microsoft.Dss.Core;
using Microsoft.Dss.Core.Attributes;

namespace VEXRobotics
{

    #region VEX Connection Status Enum
    /// <summary>
    /// VEX Connection Status
    /// </summary>
    [DataContract]
    [Description("The VEX connection state.")]
    public enum VEXConnectionStatus
    {
        /// <summary>
        /// Not Connected
        /// </summary>
        [Description("Not Connected")]
        NotConnected = 0x00,

        /// <summary>
        /// Connected Pc to VEX
        /// </summary>
        Connected = 0x01,

        /// <summary>
        /// COM port is open, but the no valid response
        /// </summary>
        ConnectedVEXToPc = 0x02,
    };
    #endregion

    /// <summary>
    /// State of the controller
    /// </summary>
    [DataContract]
    [Description("The VEX configuration state.")]
    public class VEXState : IDssSerializable, ICloneable
    {
        private int _comport;
        private int _baudrate;

        private VEXConnectionStatus _connected;
        private InterruptSensorBank _interruptSensors;
        private SensorConfig _portSensors;
        private MotorConfig _motors;

        private string _vexName;

        //for xslt
        #region For XSLT
        private string[] _availablePortSensorPorts;
        private string[] _availablePortSensorTypes;
        private string[] _availableInterruptPorts;
        private string[] _availableInterruptSensorTypes;
        private string[] _availableMotorPorts;
        private string[] _availableMotorSensorTypes;
        #endregion

        #region For XSLT
        [DataMember]
        [Browsable(false)]
        public string[] AvailablePortSensorPorts
        {
            get { return _availablePortSensorPorts; }
            set { _availablePortSensorPorts = value; }
        }
        [DataMember]
        [Browsable(false)]
        public string[] AvailablePortSensorTypes
        {
            get { return _availablePortSensorTypes; }
            set { _availablePortSensorTypes = value; }
        }

        [DataMember]
        [Browsable(false)]
        public string[] AvailableInterruptPorts
        {
            get { return _availableInterruptPorts; }
            set { _availableInterruptPorts = value; }
        }
        [DataMember]
        [Browsable(false)]
        public string[] AvailableInterruptSensorTypes
        {
            get { return _availableInterruptSensorTypes; }
            set { _availableInterruptSensorTypes = value; }
        }

        [DataMember]
        [Browsable(false)]
        public string[] AvailableMotorPorts
        {
            get { return _availableMotorPorts; }
            set { _availableMotorPorts = value; }
        }
        [DataMember]
        [Browsable(false)]
        public string[] AvailableMotorSensorTypes
        {
            get { return _availableMotorSensorTypes; }
            set { _availableMotorSensorTypes = value; }
        }
        #endregion

        /// <summary>
        /// Default constructor
        /// </summary>
        public VEXState()
        {
            // Default COM port/baud rate
            ComPort = 999;
            BaudRate = 115200;
            Connected = VEXConnectionStatus.NotConnected;

            // Initialize the state variables
            InterruptSensors = new InterruptSensorBank();
            PortSensors = new SensorConfig();
            Motors = new MotorConfig();
            VEXName = "VEX Robot";

            #region For XSLT
            InitAvailable();
            #endregion
        }

        #region For XSLT
        private void InitAvailable()
        {
            //for xslt
            AvailablePortSensorPorts = new string[17] {
                "SensorPort_None", "SensorPort_1", "SensorPort_2", "SensorPort_3", "SensorPort_4",
                "SensorPort_5", "SensorPort_6", "SensorPort_7", "SensorPort_8", "SensorPort_9",
                "SensorPort_10", "SensorPort_11", "SensorPort_12", "SensorPort_13", "SensorPort_14",
                "SensorPort_15", "SensorPort_16" };
            AvailablePortSensorTypes = new string[12] { 
                "None", 
                // Digital IO
                "DigitalInput",
                "DigitalOutput",
                "Button",
                "Limit",
                "Sonar",

                // Analog Inputs
                "AnalogInput",
                "LightSensor",
                "Potentiometer",
                "Gyro",
                "Accelerometer",
                "LineTracker"
            };

            AvailableInterruptPorts = new string[7] {
                "InteruptPort_None", " InteruptPort_1", "InteruptPort_2", "InteruptPort_3", "InteruptPort_4", "InteruptPort_5", "InteruptPort_6" };
            AvailableInterruptSensorTypes = new string[3] { "None", "Encoder", "Sonar" };

            AvailableMotorPorts = new string[9] { "MotorPort_None", "MotorPort_1", "MotorPort_2", "MotorPort_3", "MotorPort_4",
                "MotorPort_5", "MotorPort_6", "MotorPort_7", "MotorPort_8" };
            AvailableMotorSensorTypes = new string[3] { "None", "Continuous", "Servo" };
        }
        #endregion

        #region Connection

        /// <summary>
        /// COM port used
        /// </summary>
        [DataMember]
        [Description("The PC serial port used for the connection.")]
        public int ComPort
        {
            get { return this._comport; }
            set { this._comport = value; }
        }

        /// <summary>
        /// Baud rate
        /// </summary>
        [DataMember]
        [Description("The baud rate setting for the connection.")]
        public int BaudRate
        {
            get { return this._baudrate; }
            set { this._baudrate = value; }
        }

        /// <summary>
        /// Whether the connection is currently active
        /// </summary>
        [DataMember]
        [Browsable(false)]
        [Description("The connection state.")]
        public VEXConnectionStatus Connected
        {
            get { return _connected; }
            set { _connected = value; }
        }
        #endregion

        /// <summary>
        /// The interrupt port sensors
        /// </summary>
        [DataMember()]
        [Browsable(false)]
        public InterruptSensorBank InterruptSensors
        {
            get { return this._interruptSensors; }
            set { this._interruptSensors = value; }
        }

        /// <summary>
        /// The IO port sensors
        /// </summary>
        [DataMember()]
        [Browsable(false)]
        public SensorConfig PortSensors
        {
            get { return this._portSensors; }
            set { this._portSensors = value; }
        }

        /// <summary>
        /// The motors
        /// </summary>
        [DataMember()]
        [Browsable(false)]
        public MotorConfig Motors
        {
            get { return this._motors; }
            set { this._motors = value; }
        }

        /// <summary>
        /// Name of the controller
        /// </summary>
        [DataMember]
        [Description("The descriptive identifier for the VEX.")]
        public string VEXName
        {
            get { return this._vexName; }
            set { this._vexName = value; }
        }

        #region ICloneable Members
        /// <summary>
        /// Clone the VEX Bumper State
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            VEXState clone = new VEXState();

            clone.InitAvailable();
            clone.BaudRate = this.BaudRate;
            clone.ComPort = this.ComPort;
            clone.Connected = this.Connected;
            clone.InterruptSensors = (InterruptSensorBank)this.InterruptSensors.Clone();
            clone.Motors = (MotorConfig)this.Motors.Clone();
            clone.PortSensors = (SensorConfig)this.PortSensors.Clone();
            clone.VEXName = this.VEXName;

            return clone;
        }
        #endregion


        #region IDssSerializable

        /// <summary>
        /// Copy To state
        /// </summary>
        public virtual void CopyTo(IDssSerializable target)
        {
            VEXState typedTarget = target as VEXState;

            if (typedTarget == null)
                throw new ArgumentException("CopyTo({0}) requires type {0}", this.GetType().FullName);

            typedTarget.AvailableInterruptPorts = this.AvailableInterruptPorts;
            typedTarget.AvailableInterruptSensorTypes = this.AvailableInterruptSensorTypes;
            typedTarget.AvailableMotorPorts = this.AvailableMotorPorts;
            typedTarget.AvailableMotorSensorTypes = this.AvailableMotorSensorTypes;
            typedTarget.AvailablePortSensorPorts = this.AvailablePortSensorPorts;
            typedTarget.AvailablePortSensorTypes = this.AvailablePortSensorTypes;
            typedTarget.BaudRate = this.BaudRate;
            typedTarget.ComPort = this.ComPort;
            typedTarget.Connected = this.Connected;
            typedTarget.InterruptSensors = this.InterruptSensors;
            typedTarget.Motors = this.Motors;
            typedTarget.PortSensors = this.PortSensors;
            typedTarget.VEXName = this.VEXName;
        }

        /// <summary>
        /// Serialize
        /// </summary>
        public virtual void Serialize(System.IO.BinaryWriter writer)
        {
            writer.Write(this.BaudRate);
            writer.Write(this.ComPort);
            writer.Write((int)this.Connected);
            this.InterruptSensors.Serialize(writer);
            this.Motors.Serialize(writer);
            this.PortSensors.Serialize(writer);
            writer.Write(this.VEXName);
        }

        /// <summary>
        /// Deserialize
        /// </summary>
        public virtual object Deserialize(System.IO.BinaryReader reader)
        {
            this.BaudRate = reader.ReadInt32();
            this.ComPort = reader.ReadInt32();
            this.Connected = (VEXConnectionStatus)reader.ReadInt32();
            this.InterruptSensors.Deserialize(reader);
            this.Motors.Deserialize(reader);
            this.PortSensors.Deserialize(reader);
            VEXName = reader.ReadString();

            return this;
        }
        #endregion
    }


    /// <summary>
    /// Categories to group VEX services together.
    /// These categories are available for use by any Dss Service which works in conjunction with the VEX services.
    /// </summary>
    [DataContract, Description("Identifies Categories to group VEX services together.")]
    public sealed class VEXCategories
    {
        /// <summary>
        /// Indicates that the service works with the VEX controller.
        /// </summary>
        [DataMember]
        [Description("Indicates that the service works specifically with the VEX Controller service.")]
        public const string VEX = "http://schemas.vexrobotics.com/categories/robotics/VEX/vex.html";
    }
}
